﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Apache.Cassandra;
using Sandy.Uuids;

namespace Sandy
{
    public class SandyFamily
    {
        internal SandyFamily(FamilyInfo info)
        {
            Name = info.Name;
            ColumnType = info.ColumnType;
            SupercolType = info.SupercolType;
            IsSuper = info.IsSuper;
        }

        public bool IsSuper
        {
            get; private set;
        }

        public string Name
        {
            get; private set;
        }

        public ColumnType SupercolType
        {
            get; private set;
        }

        public ColumnType ColumnType
        {
            get;
            private set;
        }

        internal byte[] GetValueBytes(string value)
        {
            return Encoding.UTF8.GetBytes(value);
        }

        internal string GetValueString(byte[] value)
        {
            return Encoding.UTF8.GetString(value);
        }

        internal byte[] ColumnNameToBytes(string columnName)
        {
            return !string.IsNullOrEmpty(columnName) ? EncodeString(columnName, ColumnType) : new byte[0];
        }


        internal byte[] SuperColumnNameToBytes(string superCol)
        {
            return !string.IsNullOrEmpty(superCol) ? EncodeString(superCol, SupercolType) : new byte[0];
        }

        private static byte[] EncodeString(string value, ColumnType type)
        {
            switch (type)
            {
                case ColumnType.AsciiType:
                    return Encoding.ASCII.GetBytes(value);
                case ColumnType.LongType:
                    // Encode a big endian long
                    byte[] data = BitConverter.GetBytes(long.Parse(value));
                    if (!BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(data);
                    }
                    return data;
                case ColumnType.TimeUuidType:
                    return UuidUtils.ToBytes(value);
                case ColumnType.Utf8Type:
                    return Encoding.UTF8.GetBytes(value);
                default:
                    throw new ArgumentOutOfRangeException();
            }            
        }

        private static string DecodeBytes(byte[] value, ColumnType type)
        {
            switch (type)
            {
                case ColumnType.AsciiType:
                    return Encoding.ASCII.GetString(value);
                case ColumnType.LongType:
                    // Decode a big endian long
                    if (!BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(value);
                    }
                    long numeric = BitConverter.ToInt64(value, 0);
                    return numeric.ToString();
                case ColumnType.TimeUuidType:
                    return UuidUtils.FromBytes(value).ToString("n");
                case ColumnType.Utf8Type:
                    return Encoding.UTF8.GetString(value);
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        public string ColumnNameToString(byte[] name)
        {
            return DecodeBytes(name, ColumnType);
        }
        
        public IDictionary<string, string> CreateSupercolDict(SuperColumn superColumn)
        {
            var res = new OrderPreservingDictionary<string, string>();
            foreach (var col in superColumn.Columns)
            {
                res.Add(ColumnNameToString(col.Name),
                        GetValueString(col.Value));
            }

            return res;
        }

        public IDictionary<string, string> CreateColumnDict(List<ColumnOrSuperColumn> columns)
        {
            var res = new OrderPreservingDictionary<string, string>();

            foreach (var col in columns)
            {
                res.Add(ColumnNameToString(col.Column.Name),
                        GetValueString(col.Column.Value));
            }

            return res;
        }

        public string SuperColumnNameToString(byte[] name)
        {
            return DecodeBytes(name, SupercolType);
        }
    }
}